#include "../include/SocketIO.h"
#include "../include/Logger.h"
#include "../include/Packet.h"
#include <errno.h>
#include <stdio.h>
#include <sys/socket.h>

namespace myNameSpace {
SocketIO::SocketIO(int connectFd): _fd(connectFd) {}

int SocketIO::recvn(char *buf, int len) const {
    char *pCurr = buf;
    int left = len;
    while (left > 0) {
        int ret = recv(_fd, pCurr, left, 0);
        moqi::LOG_DEBUG("Recv %d byte.", ret);
        if (ret == -1 && errno == EINTR) {
            continue;
        }
        if (ret == -1) {
            perror("recv");
            return len - left;
        }
        if (ret == 0) {
            moqi::LOG_INFO("Thread %u: Connection[%d] disconnected.", pthread_self(), _fd);
            return len - left;
        }
        pCurr += ret;
        left -= ret;
    }
    return len;
}

int SocketIO::recvPeek(char *buf, int len) const {
    int ret = -1;
    do {
        ret = recv(_fd, buf, len, MSG_PEEK);
    } while (ret == -1 && errno == EINTR);
    if (ret == -1) {
        perror("recv");
        return ret;
    }
    if (ret == 0) {
        moqi::LOG_INFO("Thread %u: Connection[%d] disconnected.", pthread_self(), _fd);
    }
    return ret;
}

int SocketIO::readLine(char *buf, int maxLen) const {
    char *pCurr = buf;
    int left = maxLen - 1; // 预留最后一字节存放字符串结束符'\0'
    int total = 0;
    while (left > 0) {
        int ret = recvPeek(pCurr, left);
        for (int i = 0; i < ret; ++i) {
            if (pCurr[i] == '\n') {
                ret = recvn(pCurr, i + 1);
                pCurr[i] = '\0'; // 将末尾的'\n'替换为'\0'
                total += ret;
                return total;
            }
        }
        ret = recvn(pCurr, ret);
        pCurr += ret;
        left -= ret;
        total += ret;
    }
    return total;
}

int SocketIO::readPacket(Packet &packet) const {
    int total = 0;
    int ret = recvn((char *)&packet._type, sizeof(int));
    total += ret;
    if (ret < (int)sizeof(int)) {
        perror("recvn");
        return total;
    }
    moqi::LOG_DEBUG("type: %d", packet._type);
    ret = recvn((char *)&packet._length, sizeof(int));
    total += ret;
    if (ret < (int)sizeof(int)) {
        perror("recvn");
        return total;
    }
    moqi::LOG_DEBUG("length: %d", packet._length);
    char buf[1024] = {0};
    ret = recvn(buf, packet._length);
    total += ret;
    if (ret < packet._length) {
        perror("recvn");
    }
    packet._msg = string(buf, packet._length); // 使用buf的前packet._length个字符构建字符串packet._msg，即使buf中间有'\0'也不会停止
    moqi::LOG_DEBUG("type: %s", packet._msg);
    return total;
}

int SocketIO::sendn(const char *buf, int len) const {
    const char *pCurr = buf;
    int left = len;
    while (left > 0) {
        int ret = send(_fd, pCurr, left, 0);
        if (ret == -1 && errno == EINTR) {
            continue;
        }
        if (ret == -1) {
            perror("send");
            return len - left;
        }
        pCurr += ret;
        left -= ret;
    }
    return len;
}
} // end of namespace myNameSpace
